/*
 *  test/test_mmap.c
 *
 *  Harry Wei <harryxiyou@gmail.com>
 */
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define handle_error(msg)						\
	do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(int argc, char *argv[]) {
	char *addr = NULL;
	int fd;
	struct stat sb;
	off_t offset, pa_offset;
	size_t length;
	ssize_t s;

	if (argc < 3 || argc > 4) {
		fprintf(stderr, "%s file offset [length]\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	fd = open(argv[1], O_RDONLY);
	if (-1 == fd) {
		handle_error("open");
	}
	if (fstat(fd, &sb) == -1) {
		handle_error("fstat");
	}
	offset = atoi(argv[2]);
	pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
	if (offset >= sb.st_size) {
		fprintf(stderr, "offset is past end of file\n");
		exit(1);
	}
	if (argc == 4) {
		length = atoi(argv[3]);
		printf("sb.st_size is %d\n", (int) sb.st_size);
		if (offset + length > sb.st_size) {
			length = sb.st_size - offset;
		}
	} else {
		length = sb.st_size - offset;
	}
	addr = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_PRIVATE, fd, pa_offset);
	if (MAP_FAILED == addr)
		handle_error("mmap");
	s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
	if (s != length) {
		if (-1 == s) {
			handle_error("write");
		}
		fprintf(stderr, "partial write");
		exit(EXIT_FAILURE);
	}
	printf("done\n");
	exit(0);
}
